///////////////////
/// mkII - Core ///
///////////////////

#pragma once

namespace mk
{
namespace Core
{
namespace Math
{

public:
//!@ brief Four-dimensional vector class
MK_MATH_VECTOR_CLASS(Vector4)
{

// Constructors
MK_MATH_VECTOR4_CTOR( )                                                                MK_NOEXCEPT;
MK_MATH_VECTOR4_CTOR( real32 const x, real32 const y, real32 const z, real32 const w ) MK_NOEXCEPT;
MK_MATH_VECTOR4_CTOR( Vector128i   v )                                                 MK_NOEXCEPT;
MK_MATH_VECTOR4_CTOR( Vector128r   v )                                                 MK_NOEXCEPT;

// Assignment
Vector4& operator=( Vector4ConstValue v )   MK_NOEXCEPT;
Vector4& operator=( Vector128r        v )   MK_NOEXCEPT;
Vector4& operator=( Vector128i        v )   MK_NOEXCEPT;

private:
union
{
    Vector128r r;
    Vector128i i;
};

}; // class Vector4

//! @brief Equality comparison operator.
bool operator==( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Inequality comparison operator.
bool operator!=( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Less-than comparison operator.
bool operator<( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Less-equal comparison operator.
bool operator<=( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Greater-than comparison operator.
bool operator>( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Greater-equal comparison operator.
bool operator>=( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar addition operator.
Vector4 const operator+( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar subtraction operator.
Vector4 const operator-( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar multiplication operator.
Vector4 const operator*( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar division operator.
Vector4 const operator/( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar addition assignment operator.
Vector4& operator+=( Vector4& a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar subtraction assignment operator.
Vector4& operator-=( Vector4& a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar multiplication assignment operator.
Vector4& operator*=( Vector4& a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar-scalar division assignment operator.
Vector4& operator/=( Vector4& a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Unary plus operator.
Vector4 operator+( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Unary minus operator.
Vector4 operator-( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Addition of two scalars.
Vector4 const Add( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Subtraction of two scalars.
Vector4 const Sub( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Multiplication of two scalars.
Vector4 const Mul( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Division of two scalars.
Vector4 const Div( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Multiplication-addition of three vectors.
Vector4 const MAdd( Vector4ConstValue a, Vector4ConstValue b, Vector4ConstValue c ) MK_NOEXCEPT;

//! @brief Return the square root.
Vector4 const Sqrt( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Square length of the vector.
Vector4 const LengthSq( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Precise reciprocal of a scalar.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector4 const Reciprocal( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Approximate reciprocal of a scalar.
//! @details If hardware support for an estimate is available this function will use it, otherwise this
//! function is the same as the Reciprocal() function.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector4 const FastReciprocal( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Safe reciprocal of a scalar.
//! @details Get the reciprocal, if the reciprocal cannot be safely calculated (i.e. the value of the
//! vector is close or equal to zero) then return the safe reciprocal.
//! @param[in] v The vector to calculate the reciprocal of.
//! @param[in] r The 'safe' reciprocal to use if the reciprocal cannot be safely calculated.
Vector4 const SafeReciprocal( Vector4ConstValue v, Vector4ConstValue r ) MK_NOEXCEPT;

//! @brief Precise reciprocal square root of a scalar.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector4 const ReciprocalSqrt( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Approximate reciprocal square root of a scalar.
//! @details If hardware support for an estimate is available this function will use it, otherwise this
//! function is the same as the ReciprocalSqrt() function.
//! @warning Passing a zero length or very small vector \a v will produce a \b NaN.
Vector4 const FastReciprocalSqrt( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Safe reciprocal square root of a scalar.
//! @details Get the reciprocal square root, if the reciprocal of the square root of cannot be safely
//! calculated (i.e. the value of \a v is close or equal to zero) then return then the  'safe' reciprocal
//! \a r.
//! @param[in] v The vector to calculate the reciprocal square root of.
//! @param[in] r The 'safe' reciprocal square root to use if the reciprocal cannot be safely calculated.
Vector4 const SafeReciprocalSqrt( Vector4ConstValue v, Vector4ConstValue r ) MK_NOEXCEPT;

//! @brief Absolute value.
Vector4 const Abs( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Scalar modulo.
Vector4 const Mod( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar minima.
Vector4 const Min( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Scalar maxima.
Vector4 const Max( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Linear interpolation from \a a to \a b.
//! @param[in] a First value.
//! @param[in] b Second value.
//! @param[in] t The value to interpolate between \a a and \a b by.
//! @return \f$a + t(b-a)\f$
Vector4 const Lerp( Vector4ConstValue a, Vector4ConstValue b, Vector4ConstValue t ) MK_NOEXCEPT;

//! @brief Clamp a scalar to a given range.
//! @param[in] v The vector to be clamped.
//! @param[in] min The minima to clamp \a v.
//! @param[in] max The maxima to clamp \a v.
Vector4 const Clamp( Vector4ConstValue v, Vector4ConstValue min, Vector4ConstValue max ) MK_NOEXCEPT;

//! @brief Round downwards to the nearest integram value.
//! @return The rounded vector.
Vector4 const Floor( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Round upwards to the nearest integral value.
//! @return The rounded vector.
Vector4 const Ceil( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Round to the nearest integral value.
//! @return The rounded vector.
Vector4 const Round( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Bitwise OR operation.
//! @return \f$a\text{ OR }b\f$
Vector4 const Or( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise AND operation.
//! @return \f$a\text{ AND }b\f$
Vector4 const And( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise XOR operation.
//! @return \f$a\text{ XOR }b\f$
Vector4 const XOr( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise NOT operation.
//! @return \f$\text{ NOT }a\f$
Vector4 const Not( Vector4ConstValue a ) MK_NOEXCEPT;

//! @brief Bitwise AND-NOT operation.
//! @return \f$a \text{ AND }(\text{NOT }b)\f$
Vector4 const AndNot( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Bitwise selection from \a a and \a b.
//! @details Given a mask \a m and two vectors \a a and \a b, for all bits of mask \a m set to
//! \b true select the corresponding bits from \a a, select the bits from \a b otherwise.
//! @param[in] m The selection mask.
//! @param[in] a The first operand.
//! @param[in] b The second operand.
Vector4 const Select( Vector4ConstValue m, Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the equals comparison of \a a and \a b.
Vector4 const IsEqualMask( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the less than comparison of \a a and \a b.
Vector4 const IsLessMask( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the less equal comparison of \a a and \a b.
Vector4 const IsLessEqMask( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the greater than comparison of \a a and \a b.
Vector4 const IsGreaterMask( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return the mask for the greater equal comparison of \a a and \a b.
Vector4 const IsGreaterEqMask( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the mask is \b true.
//! @return \b true if the mask is \b true.
bool IsTrue( Vector4ConstValue mask ) MK_NOEXCEPT;

//! @brief Return \b true if the mask is \b false.
//! @return \b true if the mask is \b false.
bool IsFalse( Vector4ConstValue mask ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is equal to \a b.
bool IsEqual( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is less than \a b.
bool IsLess( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is less or equal to \a b.
bool IsLessEq( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is greater than \a b.
bool IsGreater( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Return \b true if the value of \a a is greater or equal to \a b.
bool IsGreaterEq( Vector4ConstValue a, Vector4ConstValue b ) MK_NOEXCEPT;

//! @brief Is the value finite.
//! @return \b true if the value is finite, \b false otherwise.
bool IsFinite( Vector4ConstValue v ) MK_NOEXCEPT;

//! @brief Loads a Vector4 from a float's address.
Vector4 const LoadVector4( real32 const* r ) MK_NOEXCEPT;

//! @brief Store a Vector4 given a destination address of a Real32.
//! @param[out] dst The address of a single float.
real32* StoreVector4( real32* dst, Vector4ConstValue v ) MK_NOEXCEPT;

} // namespace Math
} // namespace Core
} // namespace mk

#include "../../../Core/Math/Independent/mkVector4.inl"

